package com.quectel.cms.controller.partyeducationexam;


import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.http.HtmlUtil;
import com.google.common.base.Preconditions;
import com.quectel.business.common.partybuilding.PartyPersonMsgBusiness;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.cms.controller.BaseController;
import com.quectel.constant.PushConstants;
import com.quectel.constant.core.mobileuser.MobileUserMsgConstants;
import com.quectel.constant.core.partybuilding.PartyBuildingConstants;
import com.quectel.constant.core.partybuilding.PartySurveyConstants;
import com.quectel.constant.core.partyeducationexam.PartyEducationExamConstants;
import com.quectel.constant.core.partyeducationexam.PartyEducationQuestionConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.constant.sys.SysConfigKeyConstants;
import com.quectel.core.module.mobileuser.dto.MobileUserDto;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.core.module.partybuilding.dto.PartyPersonDto;
import com.quectel.core.module.partyeducationexam.dto.*;
import com.quectel.core.module.partyeducationexam.dto.ref.PersonRefExamDto;
import com.quectel.core.module.partyeducationexam.dto.ref.QuestionRefExamDto;
import com.quectel.core.module.partyeducationexam.service.PartyEducationTrainingExamPersonService;
import com.quectel.core.module.partyeducationexam.service.PartyEducationTrainingExamQuestionService;
import com.quectel.core.module.partyeducationexam.service.PartyEducationTrainingExamService;
import com.quectel.sys.module.sys.service.SysConfigService;
import com.quectel.util.common.*;
import com.quectel.util.kit.PageFetchKit;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author ryan
 * @email ryan.ran@quectel.com
 * @date 2023/06/27 15:26
 */
@RestController
@RequestMapping("partyEducationTrainingExam")
@Tag(name = "PartyEducationTrainingExamController", description = "考试相关api")
public class PartyEducationTrainingExamController extends BaseController {

    @DubboReference
    private PartyEducationTrainingExamService partyEducationTrainingExamService;
    @DubboReference
    private PartyEducationTrainingExamPersonService partyEducationTrainingExamPersonService;
    @DubboReference
    private MobileUserService mobileUserService;
    @Autowired
    private PartyPersonMsgBusiness partyPersonMsgBusiness;
    @DubboReference
    private PartyEducationTrainingExamQuestionService examQuestionService;
    @DubboReference
    private SysConfigService sysConfigService;

    /**
     * 分享请求
     *
     * @param id
     * @return
     */
    @GetMapping("share/{id}")
    @RequirePermissions(values = "partyEducationTrainingExam:info")
    @Operation(summary = "查看调查问卷分享详情")
    public Response<PartyEducationTrainingExamDto> share(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (partyEducationTrainingExamService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectById(id);
        Preconditions.checkNotNull(partyEducationTrainingExamDto);

        String gateway = sysConfigService.getConfigValueByKey(SysConfigKeyConstants.MOBILE_USER_WEB_URL);
        partyEducationTrainingExamDto.setLink(gateway + PartySurveyConstants.PARTY_EXAM + partyEducationTrainingExamDto.getId());
        return Response.<PartyEducationTrainingExamDto>ok().wrap(partyEducationTrainingExamDto);
    }

    /**
     * 导出考试题目列表
     */
    @GetMapping("exportQuestionListExcel")
    @RequirePermissions(values = "partyEducationTrainingExam:export")
    @Operation(summary = "导出考试题目列表")
    public void exportQuestionListExcel(@RequestParam Map<String, Object> params,
                                    HttpServletResponse resp) {
        super.fillAuthorityData(params);
        List<QuestionRefExamDto> partyEducationQuestionDtos = PageFetchKit.fetchAll(req -> examQuestionService.queryQuestionList(req), params, 500);
//        for (QuestionRefExamDto questionRefExamDto : list) {
//            if (questionRefExamDto.getCompleteCount() != null
//                    && questionRefExamDto.getRightCount() != null
//                    && !questionRefExamDto.getCompleteCount().equals(0)) {
//                questionRefExamDto.setAccuracy(new BigDecimal(questionRefExamDto.getRightCount() * 100 + "")
//                        .divide(new BigDecimal(questionRefExamDto.getCompleteCount() + ""), 2, RoundingMode.HALF_UP));
//            }
//        }
        String[] headers = new String[]{"所属党组织", "题库名称", "题目名称", "题目分类", "题目类型", "问题", "选项A","选项B","选项C","选项D","选项E","选项F", "答案", "解析", "是否有序", "答案关键字", "状态", "创建时间"};
        List<String[]> dataList = new ArrayList<>();
        for (PartyEducationQuestionDto data : partyEducationQuestionDtos) {
            String[] item = new String[headers.length];
            item[0] = Objects.nonNull(data.getParty()) ? data.getParty().getName() : "";
            item[1] = Objects.nonNull(data.getQuestionBank()) ? data.getQuestionBank().getName() : "";
            item[2] = data.getName();
            item[3] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_QUESTION_BANK_CLASSIFY, Objects.nonNull(data.getQuestionBank()) ? data.getQuestionBank().getClassify() + "" : "");
            item[4] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_QUESTION_TYPE, data.getType() + "");
            item[5] = Objects.nonNull(data.getTopic()) ? HtmlUtil.cleanHtmlTag(EscapeUtil.unescapeHtml4(data.getTopic())) : "";
            if (PartyEducationQuestionConstants.QuestionTypeEnum.RADIO.getType().equals(data.getType())
                    || PartyEducationQuestionConstants.QuestionTypeEnum.MULTIPLE_CHOICE.getType().equals(data.getType())) {
                // 单选题和多选题的六个选项
                List<ExamQuestionOptionCls> list = Objects.nonNull(data.getQuestionOption()) ? JacksonUtils.parseArray(data.getQuestionOption(), ExamQuestionOptionCls.class) : Lists.newArrayList();
                list.sort(Comparator.comparing(ExamQuestionOptionCls::getKey));
                for (int i = 1; i <= 6; i++) {
                    String o = "";
                    if (i <= list.size()) {
                        ExamQuestionOptionCls oc = list.get(i - 1);
                        if (oc != null) {
                            if (StringUtils.isNotBlank(oc.getContent())) {
                                o += oc.getContent();
                            }
                            if (StringUtils.isNotBlank(oc.getPicUrl())) {
                                if (StringUtils.isNotBlank(o)) {
                                    o += ",";
                                }
                                o += oc.getPicUrl();
                            }
                        }
                    }
                    item[5 + i] = o;
                }
            }
            item[12] = StringUtils.isNotBlank(data.getAnswer()) ? String.join(",", JacksonUtils.parseArray(data.getAnswer(), String.class)) : "";
            item[13] = Objects.nonNull(data.getAnalysis()) ? HtmlUtil.cleanHtmlTag(EscapeUtil.unescapeHtml4(data.getAnalysis())) : "";
            item[14] = Objects.nonNull(PartyEducationQuestionConstants.NeedOrderEnum.getDescByStatus(data.getInOrder())) ? PartyEducationQuestionConstants.NeedOrderEnum.getDescByStatus(data.getInOrder()) : "";
            item[15] = StringUtils.isNotBlank(data.getKeywords()) ? String.join(",", JacksonUtils.parseArray(data.getKeywords(), String.class)) : "";
            item[16] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.COMMON_STATUS, data.getStatus() + "");
            item[17] = Objects.nonNull(data.getCreateTime()) ? DateUtils.format(data.getCreateTime(), DateUtils.FormatType.COMMON) : "";
            dataList.add(item);
        }
        POIUtils.exportExcel(resp, "考试题目列表情况", headers, dataList, "考试题目列表情况");

    }

    /**
     * 导出考试题目统计
     */
    @GetMapping("exportQuestionExcel")
    @RequirePermissions(values = "partyEducationTrainingExam:export")
    @Operation(summary = "导出考试题目统计")
    public void exportQuestionExcel(@RequestParam Map<String, Object> params,
                                  HttpServletResponse resp) {
        super.fillAuthorityData(params);
        List<QuestionRefExamDto> list = PageFetchKit.fetchAll(req -> examQuestionService.queryQuestionList(req), params, 500);
        for (QuestionRefExamDto questionRefExamDto : list) {
            if (questionRefExamDto.getCompleteCount() != null
                    && questionRefExamDto.getRightCount() != null
                    && !questionRefExamDto.getCompleteCount().equals(0)) {
                questionRefExamDto.setAccuracy(new BigDecimal(questionRefExamDto.getRightCount() * 100 + "")
                        .divide(new BigDecimal(questionRefExamDto.getCompleteCount() + ""), 2, RoundingMode.HALF_UP));
            }
        }
        String[] headers = new String[]{"所属党组织", "题目名称", "考试名称", "题目分类", "题目类型", "正确率"};
        List<String[]> dataList = new ArrayList<>();
        for (QuestionRefExamDto data : list) {
            String[] item = new String[headers.length];
            item[0] = Objects.nonNull(data.getParty()) ? data.getParty().getName() : "";
            item[1] = data.getName();
            item[2] = data.getExamName();
            item[3] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_QUESTION_BANK_CLASSIFY, Objects.nonNull(data.getQuestionBank()) ? data.getQuestionBank().getClassify() + "" : "");
            item[4] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_QUESTION_TYPE, data.getType() + "");
            item[5] = Objects.nonNull(data.getAccuracy()) ? data.getAccuracy().toPlainString() + "%" : "";
            dataList.add(item);
        }
        POIUtils.exportExcel(resp, "考试题目统计情况", headers, dataList, "考试题目统计情况");

    }

    /**
     * 题目列表，包含答案，需要权限
     * @return
     */
    @GetMapping("questionList")
    @RequirePermissions(values = "partyEducationTrainingExam:answer")
    @Operation(summary = "题目列表 包含答案")
    public Response<Page<QuestionRefExamDto>> questionList(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "考试id") @RequestParam(required = false) Long examId
    ){
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        if (examId == null) {
            request.put(LambdaUtil.getFieldName(PartyEducationTrainingExamQuestionDto::getExamId), SystemConstants.NONEXISTENT_ID);
        }

        int total = examQuestionService.queryQuestionTotal(request.getParams());
        List<QuestionRefExamDto> list = null;
        if (total > 0) {
            list = examQuestionService.queryQuestionList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        for (QuestionRefExamDto questionRefExamDto : list) {
            if (questionRefExamDto.getCompleteCount() != null
                    && questionRefExamDto.getRightCount() != null
                    && !questionRefExamDto.getCompleteCount().equals(0)) {
                questionRefExamDto.setAccuracy(new BigDecimal(questionRefExamDto.getRightCount() * 100 + "")
                        .divide(new BigDecimal(questionRefExamDto.getCompleteCount() + ""), 2, RoundingMode.HALF_UP));
            }
        }

        Page<QuestionRefExamDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<QuestionRefExamDto>>ok().wrap(page);
    }


    /**
     * 通知
     * @param id
     * @return
     */
    @PostMapping("notify")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "通知")
    public Response<Object> notice(@RequestBody Long id){
        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectById(id);
        if (Objects.isNull(partyEducationTrainingExamDto)) {
            return Response.error("考试不存在");
        }
        if (PartyEducationExamConstants.PushStatusEnum.PUBLISHED.getStatus().equals(partyEducationTrainingExamDto.getPushStatus())) {
            return Response.error("考试已推送过，无需再次推送");
        }

        Map<String, Object> queryPersonParams = new HashMap<>();
        queryPersonParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamPersonDto::getExamId), partyEducationTrainingExamDto.getId());
        List<PersonRefExamDto> personRefExamDtos = PageFetchKit.fetchAll(req -> partyEducationTrainingExamPersonService.queryPersonList(req), queryPersonParams, 500);
        List<MobileUserDto> mobileUserDtos = personRefExamDtos.parallelStream()
                .map(o -> mobileUserService.selectByMobile(o.getMobile()))
                .filter(Objects::nonNull).collect(Collectors.toList());

        partyPersonMsgBusiness.pushMsg(
                partyEducationTrainingExamDto.getTenantId(),
                mobileUserDtos,
                MobileUserMsgConstants.SourceType.PARTY_BUILDING_TRAINING_EXAM,
                partyEducationTrainingExamDto.getId(),
                PartyBuildingConstants.PARTY_BUILDING_TRAINING_EXAM_MSG_TITLE,
                partyEducationTrainingExamDto.getName(),
                true,
                new PushConstants.PushType[]{PushConstants.PushType.WECHAT_OFFICIAL}
        );

        PartyEducationTrainingExamDto newlyDto = new PartyEducationTrainingExamDto();
        newlyDto.setId(partyEducationTrainingExamDto.getId());
        newlyDto.setPushStatus(PartyEducationExamConstants.PushStatusEnum.PUBLISHED.getStatus());
        partyEducationTrainingExamService.updateById(newlyDto);
        return Response.ok();
    }

    /**
     * 提前结束
     * @param id
     * @return
     */
    @PostMapping("end")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "提前结束")
    public Response<Object> end(@RequestBody Long id){
        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectById(id);
        if (Objects.isNull(partyEducationTrainingExamDto)) {
            return Response.error("考试不存在");
        }
        if (!PartyEducationExamConstants.StatusEnum.PUBLISHED.getStatus().equals(partyEducationTrainingExamDto.getStatus())
                || !PartyEducationExamConstants.SpecificStatusEnum.IN_PROGRESS.getStatus().equals(partyEducationTrainingExamDto.getSpecificStatus())) {
            return Response.error("考试不在进行中");
        }

        PartyEducationTrainingExamDto newlyDto = new PartyEducationTrainingExamDto();
        newlyDto.setId(partyEducationTrainingExamDto.getId());
        newlyDto.setEndTime(new Date());
        partyEducationTrainingExamService.updateById(newlyDto);
        return Response.ok();
    }

    /**
     * 发布
     * @return
     */
    @PostMapping("publish")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "发布")
    public Response<Object> publish(@RequestBody Long id){
        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectCacheById(id);
        if (Objects.isNull(partyEducationTrainingExamDto)) {
            return Response.error("考试不存在");
        }
        if (!PartyEducationExamConstants.StatusEnum.UNPUBLISHED.getStatus().equals(partyEducationTrainingExamDto.getStatus())) {
            return Response.error("考试非未发布状态");
        }

        Boolean aBoolean;
        try {
            partyEducationTrainingExamDto.setStatus(PartyEducationExamConstants.StatusEnum.PUBLISHED.getStatus());
            Map<String, Object> queryParams = new HashMap<>();
            queryParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamQuestionDto::getExamId), partyEducationTrainingExamDto.getId());
            List<QuestionRefExamDto> questionRefExamDtos = examQuestionService.queryQuestionList(queryParams);
            partyEducationTrainingExamDto.setQuestions(questionRefExamDtos);
            aBoolean = publishCheck(partyEducationTrainingExamDto);
        } catch (Exception e) {
            aBoolean = false;
        }
        if (Boolean.FALSE.equals(aBoolean)) {
            return Response.error("参数校验不通过，请检查题目设置");
        }

        PartyEducationTrainingExamDto newlyDto = new PartyEducationTrainingExamDto();
        newlyDto.setId(partyEducationTrainingExamDto.getId());
        newlyDto.setStatus(PartyEducationExamConstants.StatusEnum.PUBLISHED.getStatus());
        partyEducationTrainingExamService.updateById(newlyDto);
        return Response.ok();
    }

    /**
     * 取消
     * @return
     */
    @PostMapping("cancel")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "取消")
    public Response<Object> cancel(@RequestBody Long id){
        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectCacheById(id);
        if (Objects.isNull(partyEducationTrainingExamDto)) {
            return Response.error("考试不存在");
        }
        if (!PartyEducationExamConstants.StatusEnum.PUBLISHED.getStatus().equals(partyEducationTrainingExamDto.getStatus())) {
            return Response.error("考试非发布状态");
        }
        PartyEducationTrainingExamDto newlyDto = new PartyEducationTrainingExamDto();
        newlyDto.setId(partyEducationTrainingExamDto.getId());
        newlyDto.setStatus(PartyEducationExamConstants.StatusEnum.CANCEL.getStatus());
        partyEducationTrainingExamService.updateById(newlyDto);
        return Response.ok();
    }

    /**
     * 导出考试人员列表
     */
    @GetMapping("exportPersonExcel")
    @RequirePermissions(values = "partyEducationTrainingExam:export")
    @Operation(summary = "导出考试人员列表")
    public void exportPersonExcel(@RequestParam Map<String, Object> params,
                                  HttpServletResponse resp) {
        super.fillAuthorityData(params);
        List<PersonRefExamDto> list = new ArrayList<>();
        int pageNo = 0;
        params.put("limit", 10000);
        while (true) {
            params.put("offset", pageNo++ * 10000);
            List<PersonRefExamDto> personRefExamDtos = partyEducationTrainingExamPersonService.queryPersonList(params);
            if (CollectionUtils.isEmpty(personRefExamDtos)) {
                break;
            }
            list.addAll(personRefExamDtos);

        }
        String[] headers = new String[]{"考试名称", "所属党组织", "所属课程", "参考人", "联系电话", "最高成绩", "考试次数", "参考状态", "是否合格", "考试时间"};
        List<String[]> dataList = new ArrayList<>();
        for (PersonRefExamDto data : list) {
            String[] item = new String[headers.length];
            item[0] = data.getExamName();
            item[1] = Objects.nonNull(data.getParty()) ? data.getParty().getName() : "";
            item[2] = (Objects.nonNull(data.getExam()) && Objects.nonNull(data.getExam().getTraining())) ? data.getExam().getTraining().getName() : "";
            item[3] = data.getName();
            item[4] = data.getMobile();
            item[5] = Objects.nonNull(data.getMaxScore()) ? data.getMaxScore().toPlainString() : "";
            item[6] = Objects.nonNull(data.getTakeCount()) ? data.getTakeCount().toString() : "";
            item[7] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_TAKE_STATUS, data.getTakeStatus() + "");
            item[8] = SysCodeUtils.easyToGetName(SysCodeKeyConstants.EXAM_PASS_STATUS, data.getPassStatus() + "");
            item[9] = DateUtils.format(data.getLastExamStartTime(), DateUtils.FormatType.COMMON);
            dataList.add(item);
        }
        POIUtils.exportExcel(resp, "考试参加情况", headers, dataList, "考试参加情况");

    }

    /**
     * 参与考试人员列表
     */
    @GetMapping("personList")
    @RequirePermissions(values = "partyEducationTrainingExam:list")
    @Operation(summary = "参与考试人员列表")
    public Response<Page<PersonRefExamDto>> personList(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "考试id") @RequestParam Long examId
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = partyEducationTrainingExamPersonService.queryPersonTotal(request.getParams());

        List<PersonRefExamDto> list = null;
        if (total > 0) {
            list = partyEducationTrainingExamPersonService.queryPersonList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<PersonRefExamDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<PersonRefExamDto>>ok().wrap(page);
    }

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @RequirePermissions(values = "partyEducationTrainingExam:list")
    @Operation(summary = "分页获取考试列表")
    public Response<Page<PartyEducationTrainingExamDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = partyEducationTrainingExamService.queryTotal(request.getParams());

        List<PartyEducationTrainingExamDto> list = null;
        if (total > 0) {
            list = partyEducationTrainingExamService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<PartyEducationTrainingExamDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<PartyEducationTrainingExamDto>>ok().wrap(page);
    }

    /**
     * 编辑查询反显
     *
     * @param id
     * @return
     */
    @GetMapping("infoForEdit/{id}")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "在编辑时根据id查询考试详情")
    public Response<PartyEducationTrainingExamDto> infoForEdit(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (partyEducationTrainingExamService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectById(id);

        Map<String, Object> queryPersonParams = new HashMap<>();
        queryPersonParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamPersonDto::getExamId), partyEducationTrainingExamDto.getId());
        List<PersonRefExamDto> personRefExamDtos = PageFetchKit.fetchAll(req -> partyEducationTrainingExamPersonService.queryPersonList(req), queryPersonParams, 500);

        partyEducationTrainingExamDto.setPersons(CopyUtils.copyList(personRefExamDtos, PartyPersonDto.class));
        partyEducationTrainingExamDto.setPersonIds(personRefExamDtos.stream().map(PersonRefExamDto::getId).toArray(Long[]::new));

        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamQuestionDto::getExamId), partyEducationTrainingExamDto.getId());
        List<QuestionRefExamDto> questionRefExamDtos = examQuestionService.queryQuestionList(queryParams);

        partyEducationTrainingExamDto.setQuestions(questionRefExamDtos);

        return Response.<PartyEducationTrainingExamDto>ok().wrap(partyEducationTrainingExamDto);
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "partyEducationTrainingExam:info")
    @Operation(summary = "根据id查询考试的详情")
    public Response<PartyEducationTrainingExamDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (partyEducationTrainingExamService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectById(id);
        Map<String, Object> queryParams = new HashMap<>();
        queryParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamQuestionDto::getExamId), partyEducationTrainingExamDto.getId());
        List<QuestionRefExamDto> questionRefExamDtos = examQuestionService.queryQuestionList(queryParams);
        for (QuestionRefExamDto questionRefExamDto : questionRefExamDtos) {
            questionRefExamDto.setAnswer(null);
            questionRefExamDto.setAnalysis(null);
        }
        partyEducationTrainingExamDto.setQuestions(questionRefExamDtos);
        return Response.<PartyEducationTrainingExamDto>ok().wrap(partyEducationTrainingExamDto);
    }

    /**
     * 保存
     *
     * @param partyEducationTrainingExamDto
     * @return
     */
    @PostMapping("save")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "新增考试")
    public Response<Object> save(@RequestBody @Validated PartyEducationTrainingExamDto partyEducationTrainingExamDto) {
        if (partyEducationTrainingExamDto.getStatus() == null) {
            partyEducationTrainingExamDto.setStatus(PartyEducationExamConstants.SpecificStatusEnum.UNPUBLISHED.getStatus());
        }

        Boolean aBoolean;
        try {
            aBoolean = publishCheck(partyEducationTrainingExamDto);
        } catch (Exception e) {
            aBoolean = false;
        }
        if (Boolean.FALSE.equals(aBoolean)) {
            return Response.error("校验不通过，请检查题目设置");
        }
        //填充基础数据
        fillSaveCommonData(partyEducationTrainingExamDto);

        partyEducationTrainingExamDto.setExamPersonCount(partyEducationTrainingExamDto.getPersonIds() != null
                ? partyEducationTrainingExamDto.getPersonIds().length : 0);
        partyEducationTrainingExamDto.setExamQuestionCount(partyEducationTrainingExamDto.getQuestions() != null
                ? partyEducationTrainingExamDto.getQuestions().size() : 0);

        partyEducationTrainingExamService.save(partyEducationTrainingExamDto);

        return Response.ok();
    }

    private Boolean publishCheck(PartyEducationTrainingExamDto partyEducationTrainingExamDto) throws Exception{
        // 未发布考试可以不选择题目，发布考试必须有题，有题必须设置分数
        if (!PartyEducationExamConstants.StatusEnum.UNPUBLISHED.getStatus().equals(partyEducationTrainingExamDto.getStatus())
                && CollectionUtils.isEmpty(partyEducationTrainingExamDto.getQuestions())) {
            return Boolean.FALSE;
        }

        if (CollectionUtils.isNotEmpty(partyEducationTrainingExamDto.getQuestions())) {
            ExamQuestionSettingCls questionSettingCls = JacksonUtils.parse(partyEducationTrainingExamDto.getQuestionSetting(), ExamQuestionSettingCls.class);
            Map<Byte, List<QuestionRefExamDto>> collect = partyEducationTrainingExamDto.getQuestions().parallelStream()
                    .collect(Collectors.groupingBy(QuestionRefExamDto::getType));
            Set<Byte> types = collect.keySet();
            for (PartyEducationQuestionConstants.QuestionTypeEnum value : PartyEducationQuestionConstants.QuestionTypeEnum.values()) {
                if (types.contains(value.getType())) {
                    String fieldName = CharSequenceUtil.toCamelCase(value.name().toLowerCase());
                    ExamQuestionSettingCls.SettingCls settingCls = (ExamQuestionSettingCls.SettingCls) ReflectUtil.getFieldValue(questionSettingCls, fieldName);
                    Preconditions.checkNotNull(settingCls);

                    if (settingCls.getNumber() == null || settingCls.getNumber() != collect.get(value.getType()).size() || settingCls.getScore() == null) {
                        return Boolean.FALSE;
                    }
                }
            }
        }

        return Boolean.TRUE;
    }

    /**
     * 修改
     *
     * @param partyEducationTrainingExamDto
     * @return
     */
    @PostMapping("update")
    @RequirePermissions(values = "partyEducationTrainingExam:edit")
    @Operation(summary = "根据id修改考试")
    public Response<Object> update(@RequestBody  @Validated PartyEducationTrainingExamDto partyEducationTrainingExamDto) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(partyEducationTrainingExamDto.getId()));
        if (partyEducationTrainingExamService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        if (partyEducationTrainingExamDto.getStatus() == null) {
            partyEducationTrainingExamDto.setStatus(PartyEducationExamConstants.SpecificStatusEnum.UNPUBLISHED.getStatus());
        }

        Boolean aBoolean;
        try {
            aBoolean = publishCheck(partyEducationTrainingExamDto);
        } catch (Exception e) {
            aBoolean = false;
        }
        if (Boolean.FALSE.equals(aBoolean)) {
            return Response.error("校验不通过，请检查题目设置");
        }

        //填充基础数据
        fillEditCommonData(partyEducationTrainingExamDto);

        partyEducationTrainingExamDto.setExamPersonCount(partyEducationTrainingExamDto.getPersonIds() != null
                ? partyEducationTrainingExamDto.getPersonIds().length : 0);
        partyEducationTrainingExamDto.setExamQuestionCount(partyEducationTrainingExamDto.getQuestions() != null
                ? partyEducationTrainingExamDto.getQuestions().size() : 0);

        partyEducationTrainingExamService.updateById(partyEducationTrainingExamDto);

        return Response.ok();
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @PostMapping("delete")
    @RequirePermissions(values = "partyEducationTrainingExam:delete")
    @Operation(summary = "根据多条记录id批量删除考试")
    public Response<Object> delete(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (partyEducationTrainingExamService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }

            PartyEducationTrainingExamDto partyEducationTrainingExamDto = partyEducationTrainingExamService.selectCacheById(id);
            if (!PartyEducationExamConstants.StatusEnum.UNPUBLISHED
                    .getStatus().equals(partyEducationTrainingExamDto.getStatus())) {
                return Response.error("非未发布考试不允许删除");
            }
        }

        partyEducationTrainingExamService.deleteBatch(ids);

        return Response.ok();
    }
}
